package com.iteaj.iot.test.modbus.dtu;

import com.iteaj.iot.FrameworkManager;
import com.iteaj.iot.ProtocolType;
import com.iteaj.iot.client.IotClient;
import com.iteaj.iot.client.TcpSocketClient;
import com.iteaj.iot.client.protocol.ServerInitiativeProtocol;
import com.iteaj.iot.consts.ExecStatus;
import com.iteaj.iot.modbus.ModbusRtuOverTcpUtils;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientCommonProtocol;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientMessage;
import com.iteaj.iot.modbus.consts.ModbusCode;
import com.iteaj.iot.modbus.server.rtu.ModbusRtuBody;
import com.iteaj.iot.modbus.server.rtu.ModbusRtuHeader;
import com.iteaj.iot.modbus.server.tcp.ModbusTcpBody;
import com.iteaj.iot.modbus.server.tcp.ModbusTcpHeader;
import com.iteaj.iot.test.TestProtocolType;
import com.iteaj.iot.utils.ByteUtil;
import io.netty.buffer.Unpooled;

import java.util.concurrent.TimeUnit;

/**
 * 模拟Dtu设备请求服务端使用Modbus Rtu协议
 */
public class ModbusRtuForDtuClientTestProtocol extends ServerInitiativeProtocol<ModbusRtuForDtuClientTestMessage> {

    private ModbusTcpClientMessage tcpClientMessage;

    public ModbusRtuForDtuClientTestProtocol(ModbusRtuForDtuClientTestMessage requestMessage) {
        super(requestMessage);
    }

    /**
     * 由于Modbus Rtu使用串口通信, 所以接收到服务端的请求后转成Modbus Tcp协议请求Modbus Tcp服务
     * @see ModbusTcpClientCommonProtocol
     * @param requestMessage
     */
    @Override
    protected void doBuildRequestMessage(ModbusRtuForDtuClientTestMessage requestMessage) {
        requestMessage.getHead().setMessageId(null);
        ModbusTcpBody modbusTcpBody = ModbusRtuOverTcpUtils.toTcpBody(requestMessage.getBody());
        ModbusTcpHeader modbusTcpHeader = ModbusRtuOverTcpUtils.toTcpHeader(requestMessage.getHead(), (short) modbusTcpBody.getLength());

        ModbusTcpClientCommonProtocol commonProtocol = ModbusTcpClientCommonProtocol.build(modbusTcpHeader, modbusTcpBody);
        commonProtocol.sync(2000).request(protocol -> {
            if(protocol.getExecStatus() == ExecStatus.success) {
                ModbusCode code = modbusTcpBody.getCode();
                if(code == ModbusCode.Read03) {
                    IotClient client = FrameworkManager.getClient(requestMessage.getClass());
                    // 做拆包测试
                    if(client instanceof TcpSocketClient) {
                        ModbusRtuForDtuClientTestMessage clientTestMessage = this.buildResponseMessage(commonProtocol.responseMessage());
                        clientTestMessage.writeBuild();
                        byte[] message = clientTestMessage.getMessage();
                        if(message.length > 128) { // 拆成两包
                            byte[] bytes = ByteUtil.subBytes(message, 0, 10);
                            ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(bytes));
                            try {
                                TimeUnit.MILLISECONDS.sleep(100); // 休眠100毫秒
                                bytes = ByteUtil.subBytes(message, 10);
                                ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(bytes));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        } else {
                            ((TcpSocketClient) client).writeAndFlush(Unpooled.wrappedBuffer(message));
                        }
                    }
                } else {
                    this.tcpClientMessage = commonProtocol.responseMessage();
                }
            } else {
                logger.error("modbus over失败");
            }
            return null;
        });

    }

    @Override
    protected ModbusRtuForDtuClientTestMessage doBuildResponseMessage() {
        if(this.tcpClientMessage != null) {
            return this.buildResponseMessage(this.tcpClientMessage);
        }

        return null;
    }

    protected ModbusRtuForDtuClientTestMessage buildResponseMessage(ModbusTcpClientMessage tcpClientMessage) {
        ModbusRtuBody rtuBody = ModbusRtuOverTcpUtils.toRtuBody(tcpClientMessage.getBody());
        ModbusRtuHeader rtuHeader = ModbusRtuOverTcpUtils.toRtuHeader(tcpClientMessage.getHead());

        return new ModbusRtuForDtuClientTestMessage(rtuHeader, rtuBody);
    }

    @Override
    public ProtocolType protocolType() {
        return TestProtocolType.PIReq;
    }
}
